/*
 * AddressUnit class is composed of the address component registers and 
 * handles the Effective Address calculation.
 * 
 * Component registers are Base Address Register, Indexing Flag Register,
 * Indirection Flag Register, Address Offset Register and the 
 * Effective Address Buffer Register.
 * 
 * An effective address calculation may use the combinations of indexing and indirection
 * If indexing is specified, the the address offset will be added to the address stored in 
 * the base address; otherwise, the address offset is calculated in terms of the zero base 
 * address.  If indirection is specified, then the calculated address will be dereferenced
 * and the contents of the calculated memory address will be used as a pointer to another
 * additional memory address.
 * */

package cpu.components;

import cpu.datastores.*;

public class AddressUnit {
	// Base Address Register
	public Register16 X0;
	
	// Indexing Flag Register
	public Register1 IX;
	
	// Indirection Flag Register
	public Register1 IND;
	
	// Address Offset Register
	public Register6 ADDR;
	
	// Effective Address Buffer Register
	public Register16 EAB;
	
	// Reference to the cpu to access memory operations.
	private cpu.components.CPU cpu;
	
	public AddressUnit( cpu.components.CPU cpu ) {
		this.cpu = cpu;
		
		X0 = new Register16( );
		IX = new Register1( );
		IND = new Register1( );
		ADDR = new Register6( );
		EAB = new Register16( );
	}
	
	// Calculate Effective Address and store in EAB
	public void EA( ) {
		// EAB <- EA( )

		// if( IX == false )
		if( IX.toJavaInt( ) == 0 ) {
			
			// if( IND == false )
			if( IND.toJavaInt( ) == 0 ) {
				// if -> no indexing and no indirection
				
				// EAB <- ADDR
				int addr = ADDR.toJavaInt();
				EAB.fromSignedInteger( addr );
				cpu.cycle++;
				
				// very fast
			} else {
				// else -> no indexing but indirection
				
				// MAR <- ADDR
				cpu.memoryunit.MAR.fromSignedInteger( ADDR.toJavaInt( ) );
				cpu.controlunit.updateMemoryAddressIndicator( );
				cpu.cycle++;
				
				// Memory( get )
				cpu.memoryunit.get( );
				
				// EAB <- MBR
				EAB.fromRegister( cpu.memoryunit.MBR );
				cpu.cycle++;
				
				// moderate
			}
		} else {
			
			// if( IND == false )
			if( IND.toJavaInt( ) == 0 ) {
				// if -> indexing but no indirection

				// EAB <- X0
				EAB.fromRegister( X0 );
				cpu.cycle++;
				
				// EAB <- EAB + ADDR
				EAB.fromSignedInteger( EAB.toSignedInteger( ) + ADDR.toJavaInt( ) );
				cpu.cycle++;
				
				// somewhat fast
			} else {
				// else -> indexing and indirection
				
				// EAB <- X0
				EAB.fromRegister( X0 );
				cpu.cycle++;
				
				// EAB <- EAB + ADDR
				EAB.fromSignedInteger( EAB.toSignedInteger( ) + ADDR.toJavaInt( ) );
				cpu.cycle++;
				
				// MAR <- EAB
				cpu.memoryunit.MAR.fromRegister( EAB );
				cpu.controlunit.updateMemoryAddressIndicator( );
				cpu.cycle++;
				
				// Memory( get )
				cpu.memoryunit.get( );
				
				// EAB <- MBR
				EAB.fromRegister( cpu.memoryunit.MBR );
				cpu.cycle++;
				
				// slow
			}
		}
	}
}
